package org.meetunexpectedly.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.meetunexpectedly.constant.AuditStatus;
import org.meetunexpectedly.constant.RedisConstant;
import org.meetunexpectedly.entity.middleground.Role;
import org.meetunexpectedly.entity.middleground.UserRole;
import org.meetunexpectedly.entity.response.AuditResponse;
import org.meetunexpectedly.entity.user.Follow;
import org.meetunexpectedly.entity.video.Video;
import org.meetunexpectedly.entity.vo.UserVO;
import org.meetunexpectedly.entity.user.Favorites;
import org.meetunexpectedly.entity.user.User;
import org.meetunexpectedly.entity.user.UserSubscribe;
import org.meetunexpectedly.entity.video.Type;
import org.meetunexpectedly.entity.vo.*;
import org.meetunexpectedly.exception.BaseException;
import org.meetunexpectedly.holder.UserHolder;
import org.meetunexpectedly.mapper.user.UserMapper;
import org.meetunexpectedly.service.audit.ImageAuditService;
import org.meetunexpectedly.service.audit.TextAuditService;
import org.meetunexpectedly.service.file.FileService;
import org.meetunexpectedly.service.middleground.RoleService;
import org.meetunexpectedly.service.middleground.UserRoleService;
import org.meetunexpectedly.service.user.FavoritesService;
import org.meetunexpectedly.service.user.FollowService;
import org.meetunexpectedly.service.user.UserService;
import org.meetunexpectedly.service.user.UserSubscribeService;
import org.meetunexpectedly.service.video.InterestPushService;
import org.meetunexpectedly.service.video.TypeService;
import org.meetunexpectedly.service.video.VideoService;
import org.meetunexpectedly.util.EncryptionUtil;
import org.meetunexpectedly.util.RedisCacheUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 用户服务实现类
 * @Author: pupil
 * @Date: 2024/08/04 下午 7:18
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Autowired
    private FavoritesService favoritesService;

    @Autowired
    private EncryptionUtil encryptionUtil;

    @Autowired
    private FollowService followService;

    @Autowired
    private TypeService typeService;

    @Autowired
    private UserSubscribeService userSubscribeService;

    @Autowired
    private InterestPushService interestPushService;

    @Autowired
    private ImageAuditService imageAuditService;

    @Autowired
    private TextAuditService textAuditService;

    @Autowired
    private FileService fileService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    @Lazy
    private VideoService videoService;

    @Autowired
    private RoleService roleService;

    @Override
    public Boolean register(RegisterVO registerVO) throws Exception {
        int count = count(new LambdaQueryWrapper<User>().eq(User::getEmail, registerVO.getEmail()));
        if (count == 1) {
            throw new BaseException("邮箱已被注册");
        }
        count = this.count(new LambdaQueryWrapper<User>().eq(!ObjectUtils.isEmpty(registerVO.getNickName()), User::getNickName, registerVO.getNickName()));
        if (count == 1) {
            throw new BaseException("昵称已被使用");
        }

        String code = registerVO.getCode();
        // 从redis中查询邮箱验证码
        Object o = redisCacheUtil.get(RedisConstant.EMAIL_CODE + registerVO.getEmail());
        // 判断验证码是否过期
        if (o == null) {
            throw new BaseException("验证码已失效");
        }

        // 判断验证码是否正确
        if (!o.toString().equals(code)) {
            return false;
        }

        // 创建用户信息
        User user = new User();
        user.setEmail(registerVO.getEmail());
        // 密码进行加密后存储
        user.setPassword(encryptionUtil.encrypt(registerVO.getPassword()));
        user.setNickName(registerVO.getNickName());
        user.setDescription("这个人有点懒~~");
        // 存储用户
        this.save(user);

        // 创建默认收藏夹
        Favorites favorites = new Favorites();
        favorites.setName("默认收藏夹");
        favorites.setUserId(user.getId());
        // 存储收藏夹
        favoritesService.save(favorites);

        // 设置收藏夹id
        user.setDefaultFavoritesId(favorites.getId());
        // 更新用户信息
        this.updateById(user);
        return true;
    }

    @Override
    public Boolean ResetPassword(ForgotPwdVO forgotPwdVO) {
        // 从redis中查询邮箱验证码
        Object o = redisCacheUtil.get(RedisConstant.EMAIL_CODE + forgotPwdVO.getEmail());
        // 判断验证码是否过期
        if (o == null) {
            throw new BaseException("验证码已失效");
        }

        // 校验
        if (!o.equals(forgotPwdVO.getCode())) {
            return false;
        }

        // 修改
        User user = new User();
        user.setEmail(forgotPwdVO.getEmail());
        user.setPassword(encryptionUtil.encrypt(forgotPwdVO.getNewPassword()));
        this.update(user, new UpdateWrapper<User>().lambda().set(User::getPassword, user.getPassword()).eq(User::getEmail, user.getEmail()));
        return true;
    }

    @Override
    public UserVO getInfo(Long userId) {
        if (userId == null) {
            throw new BaseException("用户ID为空");
        }

        User user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new BaseException("用户不存在");
        }

        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);

        // 查出关注数量
        int followCount = followService.getFollowsCount(userId);
        userVO.setFollow(followCount);

        // 查出粉丝数量
        int fansCount = followService.getFansCount(userId);
        userVO.setFans(fansCount);

        return userVO;
    }

    @Override
    public Page<User> getFans(BasePage basePage, Long userId) {
        Page<User> page = new Page<>();
        // 获取粉丝列表
        Collection<Long> fansIds = followService.getFans(basePage, userId);
        if (ObjectUtils.isEmpty(fansIds)) return page;

        // 获取关注列表
        HashSet<Long> followIds = new HashSet<>();
        // 这里需要将数据转换，因为存到redis中数值小是用int保存，取出来需要用long比较
        followIds.addAll(followService.getFollows(null, userId));

        Map<Long, Boolean> map = new HashMap<>();
        // 遍历粉丝列表，查看关注列表中是否有
        for (Long fanId : fansIds) {
            map.put(fanId, followIds.contains(fanId));
        }

        // 获取粉丝的用户信息
        Map<Long, User> userMap = getBaseInfoUserToMap(map.keySet());
        ArrayList<User> users = new ArrayList<>();
        for (Long fansId : fansIds) {
            User user = userMap.get(fansId);
            user.setEach(map.get(fansId));
            users.add(user);
        }

        page.setRecords(users);
        page.setTotal(users.size());
        return page;
    }

    @Override
    public Page<User> getFollows(BasePage basePage, Long userId) {
        Page<User> page = new Page<>();

        //  获取关注列表
        Collection<Long> followsIds = followService.getFollows(basePage, userId);
        if (ObjectUtils.isEmpty(followsIds)) return page;

        // 获取粉丝列表
        HashSet<Long> fansIds = new HashSet<>();
        // 这里需要将数据转换，因为存到redis中数值小是用int保存，取出来需要用long比较
        fansIds.addAll(followService.getFans(null, userId));

        Map<Long, Boolean> map = new HashMap<>();
        // 遍历关注列表，查看粉丝列表中是否有
        for (Long followId : followsIds) {
            map.put(followId, fansIds.contains(followId));
        }

        // 获取关注人员的用户信息
        Map<Long, User> userMap = getBaseInfoUserToMap(map.keySet());
        ArrayList<User> users = new ArrayList<>();
        for (Long followsId : followsIds) {
            User user = userMap.get(followsId);
            user.setEach(map.get(followsId));
            users.add(user);
        }

        page.setRecords(users);
        page.setTotal(users.size());
        return page;
    }

    // 获取用户要映射的基本信息
    private Map<Long, User> getBaseInfoUserToMap(Collection<Long> userIds) {
        if (ObjectUtils.isEmpty(userIds)) {
            return new HashMap<>();
        }
        // 从数据库查询用户信息
        List<User> users = list(new LambdaQueryWrapper<User>().in(User::getId, userIds).select(User::getId, User::getNickName, User::getDescription
                , User::getSex, User::getAvatar));
        return users.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    }

    @Override
    public Boolean follows(Long followsUserId) {
        Long userId = UserHolder.get();
        return followService.follows(userId, followsUserId);
    }

    @Override
    public Collection<String> searchHistory(Long userId) {
        List<String> searchs = new ArrayList<>();
        if (userId != null) {
            try {
                // 从redis中获取搜索历史
                searchs.addAll(redisCacheUtil.zGet(RedisConstant.USER_SEARCH_HISTORY + userId));
                // 只返回小于等于20的数据量
                searchs = searchs.subList(0, searchs.size() < 20 ? searchs.size() : 20);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return searchs;
    }

    @Override
    public Boolean setSearchHistory(Long userId, String searchName) {
        return redisCacheUtil.zSet(RedisConstant.USER_SEARCH_HISTORY + userId, searchName, System.currentTimeMillis());
    }

    @Override
    public Boolean deleteSearchHistory(Long userId) {
        if (userId == null) {
            return false;
        }
        try {
            redisCacheUtil.del(RedisConstant.USER_SEARCH_HISTORY + userId);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    @Override
    public String subscribe(String types) {
        // 获取用户id
        Long userId = UserHolder.get();

        if (ObjectUtils.isEmpty(types)) {
            // 删除之前的订阅分类
            userSubscribeService.remove(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId));
            // 删除用户模型
            interestPushService.deleteUserModel(userId);
            return "取消订阅";
        }

        // 获取分类id集合
        HashSet<Long> typeIds = new HashSet<>();
        for (String type : types.split(",")) {
            typeIds.add(Long.parseLong(type));
        }

        // 校验分类
        Collection<Type> typesList = typeService.listByIds(typeIds);
        if (typesList.size() != typeIds.size()) {
            throw new BaseException("不存在的分类");
        }

        // 获取用户所有的订阅存储入用户订阅中间表中
        List<UserSubscribe> userSubscribes = new ArrayList<>();
        for (Long typeId : typeIds) {
            UserSubscribe userSubscribe = new UserSubscribe();
            userSubscribe.setUserId(userId);
            userSubscribe.setTypeId(typeId);
            userSubscribes.add(userSubscribe);
        }

        // 删除之前的订阅分类
        userSubscribeService.remove(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId));
        // 重新存储订阅分类
        userSubscribeService.saveBatch(userSubscribes);

        // 初始化视频推送模型
        ModelVO modelVO = new ModelVO();
        modelVO.setUserId(UserHolder.get());
        // 获取所有分类的标签
        List<String> labels = new ArrayList<>();
        for (Type type : typesList) {
            labels.addAll(type.buildLabels());
        }
        modelVO.setLabels(labels);
        initModel(modelVO);
        return "订阅成功";
    }

    @Override
    public Collection<Type> listSubscribeTypes(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }

        // 获取用户订阅分类的id
        List<Long> typeIds = userSubscribeService.list(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId))
                .stream().map(UserSubscribe::getTypeId).collect(Collectors.toList());

        if (ObjectUtils.isEmpty(typeIds)) {
            return Collections.emptyList();
        }

        // 根据用户订阅分类的id范围查询出分类，只查询出
        List<Type> types = typeService.list(new LambdaQueryWrapper<Type>()
                .in(Type::getId, typeIds)
                .select(Type::getId, Type::getName, Type::getIcon));

        return types;
    }

    @Override
    public Collection<Type> listNoSubscribeTypes(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }

        // 获取用户订阅的分类
        Set<Long> typeIds = listSubscribeTypes(userId).stream().map(Type::getId).collect(Collectors.toSet());

        // 获取所有分类
        List<Type> allType = typeService.list(null);

        List<Type> types = new ArrayList<>();

        for (Type type : allType) {
            if (!typeIds.contains(type.getId())) {
                types.add(type);
            }
        }

        return types;
    }

    @Override
    public void updateUserModel(UserModel userModel) {
        interestPushService.updateUserModel(userModel);
    }

    // 初始化模型
    private void initModel(ModelVO modelVO) {
        // 调用兴趣推送服务，初始化用户模型
        interestPushService.initUserModel(modelVO.getUserId(), modelVO.getLabels());
    }

    @Override
    public Boolean updateUser(UpdateUserVO userVO) {
        Long userId = UserHolder.get();
        User oldUser = this.getById(userId);

        if (!oldUser.getNickName().equals(userVO.getNickName())) {
            AuditResponse auditResponse = textAuditService.audit(userVO.getNickName());
            if (auditResponse.getAuditStatus() != AuditStatus.SUCCESS.num) {
                throw new BaseException(auditResponse.getMsg());
            }
            oldUser.setNickName(userVO.getNickName());
        }

        if (!ObjectUtils.isEmpty(userVO.getDescription()) && !oldUser.getDescription().equals(userVO.getDescription())) {
            AuditResponse auditResponse = textAuditService.audit(userVO.getDescription());
            if (auditResponse.getAuditStatus() != AuditStatus.SUCCESS.num) {
                throw new BaseException(auditResponse.getMsg());
            }
            oldUser.setDescription(userVO.getDescription());
        }

        if (!Objects.equals(userVO.getAvatar(), oldUser.getAvatar())) {
            AuditResponse auditResponse = imageAuditService.audit(fileService.getById(userVO.getAvatar()).getFileKey());
            if (auditResponse.getAuditStatus() != AuditStatus.SUCCESS.num) {
                throw new BaseException(auditResponse.getMsg());
            }
            oldUser.setAvatar(userVO.getAvatar());
        }

        if (!ObjectUtils.isEmpty(userVO.getDefaultFavoritesId())) {
            // 校验收藏夹
            favoritesService.exist(userId, userVO.getDefaultFavoritesId());
            oldUser.setDefaultFavoritesId(userVO.getDefaultFavoritesId());
        }

        oldUser.setSex(userVO.getSex());

        this.updateById(oldUser);
        return true;
    }

    @Override
    public IPage<User> getUserListByPage(BasePage basePage, String name) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        // 模糊查询用户条件
        wrapper.like(!ObjectUtils.isEmpty(name), User::getNickName, name);
        // 进行分页查询用户
        IPage<User> page = this.page(basePage.page(), wrapper);

        // 查出用户角色中间表，按照用户id进行分组
        Map<Long, List<UserRole>> userRoleMap = userRoleService.list(null).stream().collect(Collectors.groupingBy(UserRole::getUserId));
        // 查出角色表信息，key：roleId   value：roleName
        Map<Long, String> roleMap = roleService.list(null).stream().collect(Collectors.toMap(Role::getId, Role::getName));
        // key：userId，value：roleName的set集合
        Map<Long, Set<String>> map = new HashMap<>();
        userRoleMap.forEach((userId, userRoles) -> {
            Set<String> roles = new HashSet<>();
            for (UserRole userRole : userRoles) {
                // 获取roleName添加的roles
                roles.add(roleMap.get(userRole.getRoleId()));
            }
            map.put(userId, roles);
        });

        for (User user : page.getRecords()) {
            user.setRoleName(map.get(user.getId()));
        }

        return page;
    }

    @Override
    public Boolean deleteUser(Long id) {
        if (id == null) {
            throw new BaseException("指定用户不存在");
        }

        User user = this.getById(id);
        if (ObjectUtils.isEmpty(user)) {
            throw new BaseException("指定用户不存在");
        }

        // 判断用户的角色是否是超级管理员，超级管理员不允许删除
        List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId()).select(UserRole::getRoleId))
                .stream().map(UserRole::getRoleId).collect(Collectors.toList());
        List<Role> roles = roleService.listByIds(roleIds).stream().collect(Collectors.toList());
        for (Role role : roles) {
            if (role.getName().equals("超级管理员")) {
                throw new BaseException("超级管理员用户不允许删除");
            }
        }
        // 删除用户信息
        boolean result = this.removeById(user.getId());
        if (result) {
            // 解耦
            new Thread(() -> {
                // 删除用户的视频
                List<Long> videoIds = videoService.list(new LambdaQueryWrapper<Video>().eq(Video::getUserId, id))
                        .stream().map(Video::getId).collect(Collectors.toList());
                for (Long videoId : videoIds) {
                    videoService.deleteVideo(id);
                }
                // 删除用户角色表中的记录
                userRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, id));
                // 删除用户订阅分类
                userSubscribeService.remove(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, id));
                // 删除收藏夹
                favoritesService.remove(new LambdaQueryWrapper<Favorites>().eq(Favorites::getUserId, id));
                // 获取关注列表和粉丝列表
                Collection<Long> follows = followService.getFollows(null, id);
                Collection<Long> fans = followService.getFans(null, id);
                // 从关注者的粉丝列表中删除
                for (Long followsUserId : follows) {
                    redisCacheUtil.removeZSet(RedisConstant.USER_FANS + followsUserId, id);
                }
                // 从粉丝的关注列表中删除
                for (Long fanId : fans) {
                    redisCacheUtil.removeZSet(RedisConstant.USER_FOLLOWS + fanId, id);
                }
                // 删除自己的关注列表和粉丝列表
                redisCacheUtil.del(RedisConstant.USER_FOLLOWS + id, RedisConstant.USER_FANS + id);
                // 删除数据库中关注和粉丝的记录
                followService.remove(new LambdaQueryWrapper<Follow>().eq(Follow::getFollowId, id).or().eq(Follow::getUserId, id));

            }).start();
        }

        return result;
    }


}
